from feature_eng.alpha_series.alpha_utility import *

class Alpha_df():
    def __init__(self): 
        rd = ReadConData()  
        self.rd = rd.read_data


class Alpha_df0(Alpha_df):
    #columns = ['open', 'close', 'high', 'low', 'volume', 'amount', 'pe', 'pe_ttm',
    #    'pb', 'ps', 'ps_ttm', 'dv_ratio', 'dv_ttm', 'total_mv', 'lagret', 'vol']
    def __init__(self, ):
        super().__init__()

    def alpha_df0_0(self,):
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        return (high - low) / close

    def alpha_df0_1(self,):
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        f = (high - low) / close
        return f.rank(axis=1, pct=True)

    def alpha_df0_2(self,):
        close =  self.rd('close')
        return np.log(close/close.shift(1))

    def alpha_df0_3(self,):
        close =  self.rd('close')
        f = np.log(close/close.shift(1))
        return f.rank(axis=1, pct=True)

    def alpha_df0_4(self):
        openp = self.rd('open')
        close =  self.rd('close')
        return openp / close.shift(1)

    def alpha_df0_5(self):
        openp = self.rd('open')
        close =  self.rd('close')
        return close / openp

    def alpha_df0_6(self, ):
        high = self.rd('high')
        low = self.rd('low')
        close = self.rd('close')
        return (close - low) / (high - low)

    def alpha_df0_7(self,):
        high = self.rd('high')
        low = self.rd('low')
        openp = self.rd('open')
        return (openp - low) / (high - low)

    def alpha_df0_8(self):
        lagRet = self.rd('lagret')
        lagret_v = []
        ind_dic = industry_dict()
        for k, v in ind_dic.items():
            df_i = lagRet[v]
            rank_i  = df_i.rank(axis = 1, pct=True)
            lagret_v.append(rank_i)
        lagRet_vol = pd.concat(lagret_v, axis=1)
        lagRet_vol = lagRet_vol[lagRet.columns]
        return lagRet_vol

    def alpha_df0_9(self):#特殊
        lagRet = self.rd('total_mv')
        lagret_v = []
        ind_dic = industry_dict()
        for i in lagRet.columns:
            for k, v in ind_dic.items():
                if i in v:
                    v_i = lagRet[i] / lagRet[v].sum(axis=1)
                    lagret_v.append(v_i)
        lagRet_vol = pd.concat(lagret_v, axis=1)
        lagRet_vol.columns = lagRet.columns
        return lagRet_vol

    def alpha_df0_10(self):
        close =  self.rd('close')
        return ser_expand_rank(close)

    def alpha_df0_11(self):
        volume =  self.rd('volume')
        return ser_expand_rank(volume)

class Alpha_df1(Alpha_df):
    #columns = ['open', 'close', 'high', 'low', 'volume', 'amount', 'pe', 'pe_ttm',
    #    'pb', 'ps', 'ps_ttm', 'dv_ratio', 'dv_ttm', 'total_mv', 'lagret', 'vol']
    def __init__(self, ):
        super().__init__()

    def alpha_df1_1(self, N):
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        f = (high - low) / close
        return ser_rank(f, N)

    def alpha_df1_2(self, N):
        close =  self.rd('close')
        f = np.log(close/close.shift(1))
        return ser_rank(f, N)

    def alpha_df1_3(self, N):
        close =  self.rd('close')
        f = np.log(close/close.shift(1))
        f = sum_roll(f, N)
        return f.rank(axis=1, pct=True)
        
    def alpha_df1_4(self, N):
        openp = self.rd('open')
        close =  self.rd('close')
        f = openp / close.shift(1)
        return ser_rank(f, N)

    def alpha_df1_5(self, N):
        high = self.rd('high')
        low = self.rd('low')
        openp = self.rd('open')
        f = (openp - low) / (high - low)
        return ser_rank(f, N)

    def alpha_df1_6(self, N):
        close = self.rd('close')
        return close/max_roll(close, N)

    def alpha_df1_7(self, N):
        close = self.rd('close')
        return close/min_roll(close, N)

    def alpha_df1_8(self, N):
        lagret = self.rd('lagret')
        return sum_roll(lagret, N)/sum_roll(abs(lagret), N)

    def alpha_df1_9(self, N): 
        close = self.rd('close')
        high = self.rd('high')
        low = self.rd('low')
        m = (high + low + 2*close)/4
        p = close - m   
        return p/ma_roll(p, N)

    def alpha_df1_10(self, N):
        lagret = self.rd('lagret')
        up = sign_p(lagret)
        down = sign_n(lagret)
        return  sum_roll(up-down, N) / N

    def alpha_df1_11(self,N):
        close = self.rd('close')
        high = self.rd('high')
        low = self.rd('low')
        f=(ma_roll(close,N)/std_roll(close,N))*np.log(ma_roll(close, N)/(max_roll(high, N)-min_roll(low, N)))
        return f

    def alpha_df1_12(self, N):
        a = 1.5
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        c_std = std_roll(close,N)
        c_h = max_roll(high, N)
        c_l = min_roll(low, N)
        c_0 = close.shift(N)          
        condition1 = (np.minimum(c_h.values-c_0.values, c_h.values-close.values) > (a * c_std.values)).astype(int)
        condition2 = (np.minimum(c_0.values-c_l.values, close.values-c_l.values) > (a * c_std.values)).astype(int)   
        # print("同时成立:",((condition1+condition2)>=2).any()) 
        f = (condition2 - condition1)
        f = pd.DataFrame(f, index=close.index, columns=close.columns)
        return f

    def alpha_df1_13(self, N):
        openp = self.rd('open')
        close =  self.rd('close')
        up = sign_p(openp - close.shift(1))
        down = sign_n(openp - close.shift(1))
        return sum_roll(up-down, N) / N

    def alpha_df1_14(self, N):
        close =  self.rd('close')
        volume =  self.rd('volume')
        return sum_roll(close*volume, N)/sum_roll(volume, N)

    def alpha_df1_15(self, N):
        close =  self.rd('close')
        volume =  self.rd('volume')
        vwap = sum_roll(close*volume, N)/sum_roll(volume, N)
        return (vwap - min_roll(close, N))/(max_roll(close, N) - min_roll(close, N))

    def alpha_df1_16(self, N):
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        h_N = max_roll(high, N).shift(1)
        l_N = min_roll(low, N).shift(1)
        return np.maximum(0, close / h_N - 1) - np.minimum(0, close / l_N - 1)

    def alpha_df1_17(self, N):
        high =  self.rd('high')
        low =  self.rd('low')
        h_N = max_roll(high, N).shift(1)
        l_N = min_roll(low, N).shift(1)
        return np.maximum(0, low / h_N - 1) - np.minimum(0, high / l_N - 1)

    def alpha_df1_18(self, N):
        close =  self.rd('close')
        return ser_rank(close, N)

    def alpha_df1_19(self, N):
        volume =  self.rd('volume')
        return ser_rank(volume, N)

    def alpha_df1_20(self, N):
        close =  self.rd('close')
        lagret = self.rd('lagret')
        nan_count = lagret.shape[1] -  np.isnan(lagret).sum(axis=1).values
        one_array = np.ones(lagret.values.shape)
        sign_df = sign_p(lagret>0.09)
        f = one_array*np.expand_dims(sign_df.sum(axis=1).values, axis=1) / np.expand_dims(nan_count, axis=1)
        return pd.DataFrame(f, index=lagret.index, columns=lagret.columns) - ser_rank(close, N)

    def alpha_df1_21(self, N):
        close =  self.rd('close')
        lagret = self.rd('lagret')
        nan_count = lagret.shape[1] - np.isnan(lagret).sum(axis=1).values
        one_array = np.ones(lagret.values.shape)
        sign_df = sign_p(lagret<-0.09)
        f = one_array*np.expand_dims(sign_df.sum(axis=1).values, axis=1) / np.expand_dims(nan_count, axis=1)
        return pd.DataFrame(f, index=lagret.index, columns=lagret.columns) - ser_rank(close, N)


        
class Alpha_df2(Alpha_df):
    def __init__(self, ):
        super().__init__()

    def alpha_df2_0(self, s, l):
        close = self.rd('close')
        return ma_short_to_long(close, s, l)

    def alpha_df2_1(self, s, l):
        close = self.rd('close')
        f = ma_short_to_long(close, s, l)
        return f.rank(axis=1, pct=True)

    def alpha_df2_2(self, s, l):
        volume = self.rd('volume')
        return ma_short_to_long(volume, s, l)

    def alpha_df2_3(self, s, l):
        volume = self.rd('volume')
        f = ma_short_to_long(volume, s, l)
        return f.rank(axis=1, pct=True)

    def  alpha_df2_4(self, s, l):   
        high =  self.rd('high')
        low =  self.rd('low')
        h_mean_s_N = ma_roll(high, s)
        h_mean_l_N = ma_roll(high, l)
        l_mean_s_N = ma_roll(low, s)
        l_mean_l_N = ma_roll(low, l)          
        high_ratio = (h_mean_s_N >= h_mean_l_N ) * (np.divide((h_mean_s_N - h_mean_l_N), h_mean_l_N))
        low_ratio = (l_mean_s_N <= l_mean_l_N ) * (np.divide(( l_mean_l_N - l_mean_s_N), l_mean_l_N))     
        f = high_ratio - low_ratio
        return f
    
    def alpha_df2_5(self, s, l): 
        close = self.rd('close')
        high = self.rd('high')
        low = self.rd('low')
        m = (high + low + 2*close)/4
        p = close - m   
        return ma_roll(p, s)/ma_roll(p, l)
        
    def alpha_df2_6(self, s, l):
        close =  self.rd('close')
        volume =  self.rd('volume')
        vwaps = sum_roll(close*volume, s)/sum_roll(volume, s)
        vwapl = sum_roll(close*volume, l)/sum_roll(volume, l)
        return vwaps / vwapl

    def alpha_df2_7(self, s, l):
        lagret = self.rd('lagret')
        return std_roll(lagret, s)/std_roll(lagret, l) 
    

class Alpha_df3(Alpha_df):
    def __init__(self, ):
        super().__init__()

    def alpha_df3_0(self, c, p, n):
        close = self.rd('close')
        return ma_cur_to_pre(close, c, p, n)

    def alpha_df3_1(self, c, p, n):
        volume = self.rd('volume')
        return ma_cur_to_pre(volume, c, p, n)
    
    def alpha_df3_2(self, c, p, n): 
        close = self.rd('close')
        high = self.rd('high')
        low = self.rd('low')
        m = (high + low + 2*close)/4
        d = close - m   
        return ma_roll(d, c)/ma_roll(d, p).shift(n)
        
    def alpha_df3_3(self, c, p, n):
        close =  self.rd('close')
        volume =  self.rd('volume')
        vwaps = sum_roll(close*volume, c)/sum_roll(volume, c)
        vwapl = sum_roll(close*volume, p)/sum_roll(volume, p)
        return vwaps / vwapl.shift(n)

class Alpha_df_stat(Alpha_df):
    def __init__(self):
        super().__init__()

    def alpha_df_stat_0(self, target, N):
        close =  self.rd('close')
        high =  self.rd('high')
        low =  self.rd('low')
        lagRet_vol = (high - low) / close
        if  target == "max":
            signal = lagRet_vol.rolling(N, min_periods=1).max()
        if  target == "min":
            signal =lagRet_vol.rolling(N, min_periods=1).min()
        if  target == "mean":
            signal =lagRet_vol.rolling(N, min_periods=1).mean()
        if  target == "median":
            signal =lagRet_vol.rolling(N, min_periods=1).median()
        if  target == "skew":
            signal =lagRet_vol.rolling(N, min_periods=1).skew()
        if  target == "kurt":
            signal =lagRet_vol.rolling(N, min_periods=1).kurt()
        return signal

    def alpha_df_stat_1(self, target, N):#特殊
        lagRet_vol = self.rd('lagret')/self.rd('vol')
        if  target == "max":
            signal = lagRet_vol.rolling(N, min_periods=1).max()
        if  target == "min":
            signal =lagRet_vol.rolling(N, min_periods=1).min()
        if  target == "mean":
            signal =lagRet_vol.rolling(N, min_periods=1).mean()
        if  target == "median":
            signal =lagRet_vol.rolling(N, min_periods=1).median()
        if  target == "skew":
            signal =lagRet_vol.rolling(N, min_periods=1).skew()
        if  target == "kurt":
            signal =lagRet_vol.rolling(N, min_periods=1).kurt()
        return signal

    def alpha_df_stat_2(self, target, N):#特殊
        lagRet = self.rd('lagret')
        lagret_v = []
        ind_dic = industry_dict()
        for i in lagRet.columns:
            for k, v in ind_dic.items():
                if i in v:
                    v_i = lagRet[i] - lagRet[v].mean(axis=1)
                    lagret_v.append(v_i)
        lagRet_vol = pd.concat(lagret_v, axis=1)
        lagRet_vol.columns = lagRet.columns
        if  target == "max":
            signal = lagRet_vol.rolling(N, min_periods=1).max()
        if  target == "min":
            signal =lagRet_vol.rolling(N, min_periods=1).min()
        if  target == "mean":
            signal =lagRet_vol.rolling(N, min_periods=1).mean()
        if  target == "median":
            signal =lagRet_vol.rolling(N, min_periods=1).median()
        if  target == "skew":
            signal =lagRet_vol.rolling(N, min_periods=1).skew()
        if  target == "kurt":
            signal =lagRet_vol.rolling(N, min_periods=1).kurt()
        return signal


        

    